
package com.feib.ebilling.job;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.feib.ebilling.job.service.FtpService;
import com.feib.ebilling.job.service.TelnetService;
import com.feib.ebilling.job.service.ThirdPartyFeedbackService;


/**
 * @title (#)ThirdPartyFeedback.java<br>
 * @description 其他代收通路銷帳批次回饋<br>
 * @author Jimmy Liu<br>
 * @version 1.0.0 2010/11/25
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2010/12/10 create by Jimmy Liu<br>
 */
@Service("thirdPartyFeedback")
public class ThirdPartyFeedback {


    public static Logger logger = LoggerFactory.getLogger(ThirdPartyFeedback.class);

    public static final SimpleDateFormat BASIC_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    public static List<String> DEFAULT_CHANNELS;
    static
    {
        DEFAULT_CHANNELS = new ArrayList<String>();
        DEFAULT_CHANNELS.add("7111111");
        DEFAULT_CHANNELS.add("TFM");
        DEFAULT_CHANNELS.add("HILIFE");
        DEFAULT_CHANNELS.add("OKCVS");
        DEFAULT_CHANNELS.add("POST");
        /* 20120521  增加 ACH 通路銷帳 */
        DEFAULT_CHANNELS.add("ACH");
        
    }
    
    /**
     * 代收手續費代碼
     */
    private List<String> commissionCodes;

    @Resource(name="thirdPartyFeedbackService")
    private ThirdPartyFeedbackService thirdPartyFeedbackService;

    @Resource(name="ftpService")
    private FtpService ftpService;
    
    @Resource(name="telnetService")
    private TelnetService telnetService;

    /* 讀取FTP設定檔 */
    @Resource(name="ftpProperties")
    private Properties ftpProperties;


    /**
     * 其他代收通路銷帳批次回饋
     * @param args array, args[0]通路代號  args[1]西元日期<br>
     */
    public static void main(String[] args) {

        /* 所有通路 */
        List<String> channels = DEFAULT_CHANNELS;

        /* 傳輸日期 --> 系統日前一日 */
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        Date dNow = new Date();
        long t = dNow.getTime();
        t -= 24*60*60*1000; 
        Date then = new Date(t);
        String processDate = dateFormat.format(then);
        String CommissionCodes = "";

        
      
        if (null == args || 0 == args.length)
        {
            // do nothing.
            /* 處理系統日當日所有通路 */
        }
        else
        {
            /* 指定通路 */
            channels = new ArrayList<String>();
            channels.add(args[0]);

            if (1 == args.length)
            {
                // do nothing.
                /* 指定通路，系統日 */
            }
            else
            {
            	if (3 == args.length){
                    /* 指定通路參數[0]，指定日期參數[1]，指定手續費代碼參數[2]*/
                    processDate = args[1]; 
                    CommissionCodes = args[2];
                }else{
                	/* 指定通路參數[0]，指定日期參數[1]  */
                	processDate = args[1];
                }	
            }
        }

        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                        new String[] {"applicationContext-config.xml", "applicationContext-dao.xml", "applicationContext-properties.xml"});

        Date start = new Date();
        logger.info("[開始] 其他代收通路銷帳批次回饋  - {}", BASIC_DATE_TIME_FORMAT.format(start));
        try {
            ThirdPartyFeedback thirdPartyFeedback = (ThirdPartyFeedback)ctx.getBean("thirdPartyFeedback");
            
            /* 代收手續費代碼 */
            List<String> codes = thirdPartyFeedback.getCommissionCodes();            
                  
            if  (!CommissionCodes.trim().equals("")){
            	 /* 指定手續費代碼 */
                 codes.clear();
                 codes.add(CommissionCodes);
            } 
            if  (args[0].equals("POST")){
           	     /* 郵局手續費代碼 */
                 codes.clear();
                 codes.add("ZZZ");
            }
            /* 20120521  增加 ACH 通路銷帳 */
            if  (args[0].equals("ACH")){
                 codes.clear();
                 /* 沒指定代碼就設定ACH */
                 codes.add("ACH"); 
            }    
          
            int i = 1;
            for(String channel : channels)
            {
                for (String code : codes)
                {
                	try {
                    	logger.info("{}.",i++);
                    	/* ACH 不走檔案 ， 走資料庫查詢 */
                    	if  (channel.trim().equals("ACH")){                    		
                    		/*
                    		 * 需先檢核T+1是不是營業日,不是就不處理  
                    		 * 並取回前一個營業日 sLastBussinessDay 當成F101的查詢日期。
                    		 */                    		
                    		String sLastBussinessDay = thirdPartyFeedback.getHoliday(processDate);
                    		  
                    		/* 無法取得營業日資料時， 視為程式執行錯誤 */
                    		if (null==sLastBussinessDay){
                    		    logger.error("無法取得processDate: " + processDate + " 是否為營業日 ");   
                    	        return ;
                    		}    
                    	    /* 是假日 不處理 跳出 */      
                    	    if ("000001".equals(sLastBussinessDay)){ 
                    	        logger.info("回饋日processDate: " + processDate + " 為假日,不回饋檔案  ");             
                    	        return ;   
                    	    }
                    	    /* 前一個營業日 sLastBussinessDay 當成F101的查詢日期。格式已經是民國年 */
                    	    processDate = sLastBussinessDay;                    	      
                    		thirdPartyFeedback.executeByDB(channel, processDate, code);
                    	}else{                   
                    		thirdPartyFeedback.execute(channel, processDate, code);   
                    	}
                	}
                    catch (Exception e) {
                        Object[] objs = new Object[]{channel, processDate, code};
                        logger.error("[錯誤] 通路:{}, 日期:{}, 交易代號{}, 銷帳錯誤！", objs);
                        logger.error("[錯誤]" + e.toString(), e);
                    }
                }                
            }
        }
        catch (Exception e) {
            logger.error("[錯誤]" + e.getMessage(), e);
        }
        finally{
            Date end = new Date();
            logger.info("[結束] 其他代收通路銷帳批次回饋  - {}", BASIC_DATE_TIME_FORMAT.format(start));
            logger.info("共費時 - " + ((end.getTime() - start.getTime()) / 1000) + " 秒");
        }
    }

    public void execute(String channel, String processDate, String commissionCode) throws IOException
    {
        Assert.notNull(channel, "[錯誤]代收通路 can't be null.");
        Assert.notNull(processDate, "[錯誤]傳輸日期  can't be null.");
        
        logger.info("************************************************");
        logger.info("代收通路：{}", channel);
        logger.info("傳輸日期：{}", processDate);
        logger.info("代收手續費代碼：{}", commissionCode);


        String fileName = null;
        String fileName2 = null;
        String fileName3 = null;
        if ("7111111".equals(channel)){
            /* 統一超商傳輸檔名：SPXXX0.yyyymmdd */
            fileName = "SP" + commissionCode + "0." + processDate;                           
        }else if ("TFM".equals(channel)){
            /* 全家超商傳輸檔名：TFMXXX.yyyymmdd */
            fileName = "TFM" + commissionCode + "." + processDate;    
        }else if ("HILIFE".equals(channel)){    
            /* 萊爾富超商傳輸檔名：HLFXXX.yyyymmdd */
            fileName = "HLF" + commissionCode + "." + processDate;   
        }else if ("OKCVS".equals(channel)){     
            /* OK超商傳輸檔名：OKMXXX.yyyymmdd */
            fileName = "OKM"+commissionCode +"." + processDate;   
        }else if ("POST".equals(channel)){
            /* 郵局傳輸檔名：POSTnewyyyymmdd */
        	fileName = "POSTnew" + processDate;
        	fileName2 = "POSTeBilling" + processDate;
        	fileName3 = "POSTMerge" + processDate;
        	
        } 
        else{
            logger.error("無此代收通路： {}", channel);
            return;
        }
        
        // 檢核是否已經有檔名相同且已處理過了
        if (this.thirdPartyFeedbackService.hasWriteoff(fileName))
        {
            logger.error("[錯誤]檔名 {} 於資料表FEEDBACK_LOG 中已有銷帳成功紀錄.", fileName);
            return ;
        }
        else
        {
            logger.info("刪除繳款通路銷帳日誌, 檔名 {}", fileName);
            this.thirdPartyFeedbackService.deleteLogsByFileName(fileName);
        }

        logger.info("傳輸檔案：{}", fileName);
        if (ftpService.retryGetFtpFile(channel, fileName)){
            
            // 改抓取 ftp properties 設定
            String localFolderProperty = ftpProperties.getProperty(channel + "#LocalFolder");

            File FtpFile = new File(localFolderProperty + "/" + fileName);
            if(FtpFile.exists()){
            	
            	/* 郵局檔案，需要併檔 */
            	if (fileName2 != null){
            		logger.info("郵局合併檔案開始");
            		if (ftpService.retryGetFtpFile(channel, fileName2)){
	           			 File FtpFile2 = new File(localFolderProperty + "/" + fileName2);
	           			 if(FtpFile2.exists()){
	           				  if (mergeFile(new FileReader(localFolderProperty + "/" + fileName),
	           				                new FileReader(localFolderProperty + "/" + fileName2),
	           				                localFolderProperty + "/" +fileName3)){
	           					  logger.info("郵局合併檔案成功：{}", fileName3);
	           					  fileName = fileName3;
	           				  }else{
	           					  logger.info("郵局合併檔案失敗：{}", fileName3);
	           					  return;  
	           				  }
	           			 }else{
	           				  /* 無下載檔案資料 */ 
	                          logger.error("[錯誤]Open {}/{} failed.", localFolderProperty, fileName2);   
	           			 }           			
	           		}else{
	           			logger.error("[錯誤]無法取得檔案：{}" , fileName2); 
	           		}
            	}            	
            	
                BufferedReader in = new BufferedReader(new FileReader(localFolderProperty + "/" + fileName));
                logger.info("Read file : {}/{}", localFolderProperty, fileName);

                String str = "";
                String trxAcct ="";
                String trxDate = "";
                String trxStore ="";
                String trxAmount = "";
                String trxBarcode1 = "";
                String trxBarcode2 = "";
                String trxBarcode3 = "";

                long totalcount = 0;
                long totalamount = 0;

                while ((str = in.readLine()) != null) {
                    if (! "POST".equals(channel)){
                        /* ---- 超商格式 ---- */ 
                        /* 明細 */
                        if (str.substring(0,1).equals("2")){                                                    
                            /* 代收門市店號 */
                            trxStore = str.substring(17,25).trim();                                                         
                            /* 顧客繳費日 */
                            trxDate = str.substring(52,60); //這裡是西元年月日
                            /* 三段式條碼 */
                            trxBarcode1 = str.substring(60,69).trim();                                                      
                            trxBarcode2 = str.substring(69,89).trim();
                            trxBarcode3 = str.substring(89,104).trim();
                            /* 交易金額 */
                            trxAmount = trxBarcode3.substring(6,15); 

                            /* 交易筆數加總*/
                            totalcount++;

                            /* 交易金額加總 */
                            totalamount = totalamount + Long.parseLong(trxAmount);

                            Map<String, Object> feedBackLog = createEmptyFeedbackLog();
                            feedBackLog.put("FBFILENAME", fileName);
                            feedBackLog.put("CHANNEL", channel);                            
                            feedBackLog.put("STORE", trxStore);
                            feedBackLog.put("ADAY", trxDate);
                            feedBackLog.put("BARCDOE1", trxBarcode1);
                            feedBackLog.put("BARCDOE2", trxBarcode2);
                            feedBackLog.put("BARCDOE3", trxBarcode3);
                            feedBackLog.put("TXAMT", trxAmount);

                            feedBackLog.put("USERNO", trxBarcode2);//虛擬帳號
                            feedBackLog.put("ATIME", "00000000");//顧客繳費時間
                            feedBackLog.put("FEEDBACK_TYPE", new Integer(2)); //回饋種類2 : thirdParty(便利商店、郵局等)
                            feedBackLog.put("FBTIME", new Date()); //銷帳時間
                            feedBackLog.put("FBCODE", "0");//銷帳結果                            

                            /* Insert to 銷帳Log Table 檔名 + 上面所有資料*/
                            this.thirdPartyFeedbackService.addFeedbackLog(feedBackLog);
                        }
                        /* 結尾 */
                        if (str.substring(0,1).equals("3")){
                        	if (str.trim().length() != 54){
                        		logger.error("銷帳失敗，檔案尾錄長度不符：" + str.length());
	                            /* Delete 銷帳Log Table 資料 */
	                            this.thirdPartyFeedbackService.removeFeedbackLog(fileName);
                        	}else{
	                            if  (totalcount == Long.parseLong(str.substring(44,54)) && 
	                                 totalamount == (Long.parseLong(str.substring(28,44)) / 100) ){
	                                logger.info("銷帳總筆數：{}", totalcount);
	                                logger.info("銷帳總金額：{}", totalamount);
	
	                            }else{                                                                   
	                                logger.error("銷帳總筆數：{}", totalcount);
	                                logger.error("銷帳總金額：{}", totalamount);     
	                                logger.error("尾錄總筆數：{}", Long.parseLong(str.substring(44,54)));
	                                logger.error("尾錄總金額：{}", Long.parseLong(str.substring(28,44)) / 100);
	                                logger.error("銷帳失敗，檔案金額筆數不符");  
	
	                                /* Delete 銷帳Log Table 資料 */
	                                this.thirdPartyFeedbackService.removeFeedbackLog(fileName);
	                            }
                        	}     
                        }

                    }else{
                        /* ---- 郵局格式 ---- */  
                    	
                    	/* 劃撥帳號 (元智固定為17105626) */
                    	trxAcct = str.substring(0,8);
                        /* 經辦局號 */
                        trxStore = str.substring(15,21);
                        /* 顧客繳費日(民國年轉西元年) */
                        trxDate = String.valueOf((Integer.parseInt(str.substring(8,11)) + 1911));
                        trxDate = trxDate + str.substring(11,15);                        
                        /* 用戶號碼(20110615元智為學號、20110719變更為繳費帳號 ) */                                              
                        trxBarcode3 = str.substring(44,68).trim();
                        /* 交易金額 */                        
                        trxAmount =  str.substring(33,44);
                        
                        if (str.substring(32,33).equals("-")){
                        	logger.error("存提別為提，不知如何處理??{}" , "-");
                        }else{
                        	logger.info(trxBarcode3 + " 存 ({}):{}", str.substring(32,33), trxAmount);
                        }

                        /* 交易筆數加總*/
                        totalcount++; 
                        /* 交易金額加總 */
                        totalamount = totalamount + Long.parseLong(trxAmount);

                        Map<String, Object> feedBackLog = createEmptyFeedbackLog();
                        feedBackLog.put("FBFILENAME", fileName);
                        feedBackLog.put("CHANNEL", channel); 
                        feedBackLog.put("ATMID", trxAcct);
                        feedBackLog.put("STORE", trxStore);
                        feedBackLog.put("ADAY", trxDate);
                        feedBackLog.put("BARCDOE3", trxBarcode3);
                        feedBackLog.put("TXAMT", trxAmount);

                        feedBackLog.put("USERNO", trxBarcode3);//虛擬帳號
                        feedBackLog.put("ATIME", "00000000");//顧客繳費時間
                        feedBackLog.put("FEEDBACK_TYPE", new Integer(2)); //回饋種類2 : thirdParty(便利商店、郵局等)
                        feedBackLog.put("FBTIME", new Date()); //銷帳時間
                        feedBackLog.put("FBCODE", "0");//銷帳結果 

                        /* Insert to 銷帳Log Table 檔名 + 上面所有資料*/  
                        this.thirdPartyFeedbackService.addFeedbackLog(feedBackLog);  
                    }
                }
                logger.info("銷帳總筆數：{}", totalcount);
                logger.info("銷帳總金額：{}", totalamount);
                in.close();
                doWriteOff(channel, fileName);
            }
            else
            {
                /* 無下載檔案資料 */ 
                logger.error("[錯誤]Open {}/{} failed.", localFolderProperty, fileName);  
            }
        }
        else
        {
            logger.error("[錯誤]無法取得檔案：{}" , fileName);      
        }
    }
    
    private static boolean mergeFile(Reader file1, Reader file2, String fileanme) {
    	
    	BufferedReader br1 = new BufferedReader(file1);
    	BufferedReader br2 = new BufferedReader(file2);
    	
    	try {
    		String temp1 = "";
    		String temp2 = ""; 
    		String str = "";
    		String trxAmount = "";
    		int totalcount = 0;
    		long totalamount = 0;    		
    		while ((str = br1.readLine()) != null) {
	    		temp1 = temp1 + str + "\r\n"; 
	    		 /* 交易金額 */                        
                trxAmount =  str.substring(33,44);
                /* 交易筆數加總*/
                totalcount++; 
                /* 交易金額加總 */
                totalamount = totalamount + Long.parseLong(trxAmount);
	    	} 
    		logger.info("1.POSTnew");
    		logger.info("1.銷帳總筆數：{}", totalcount);
            logger.info("1.銷帳總金額：{}", totalamount);
            totalcount = 0;
    		totalamount = 0;  
    		while ((str = br2.readLine()) != null) {
	    		temp2 = temp2 + str + "\r\n";
	    		 /* 交易金額 */                        
                trxAmount =  str.substring(33,44);
                /* 交易筆數加總*/
                totalcount++; 
                /* 交易金額加總 */
                totalamount = totalamount + Long.parseLong(trxAmount);
	        }
    		logger.info("2.POSTeBilling");
    		logger.info("2.銷帳總筆數：{}", totalcount);
            logger.info("2.銷帳總金額：{}", totalamount);
	    	String temp = temp1 + temp2;
	    	FileWriter fw = new FileWriter(fileanme);
	    	char buffer[]=new char[temp.length()];
	    	temp.getChars(0,temp.length(),buffer,0);  
	    	fw.write(buffer);    	
	    	fw.close();
	    	return true;
    	}catch (Exception ex){
            logger.error("[錯誤]" + ex.toString(), ex);  
            return false;
        }
    }

    public List<String> getCommissionCodes()
    {
    	boolean bflag = false;    	
    	/* 20120117 網路問題目前無解
    	 * 有時會發生連接到主機 10.48.101.84 的 TCP/IP 連接已經失敗。
    	 * 錯誤: "connect timed out 
    	 */
    	int i=0;
    	while (bflag == false){
    		/* 確認資料庫是OK的 */
    		bflag = telnetService.connect();
    		i++;
    		if (bflag == false) {
	    		if (i < 5){
	    		    logger.info("資料庫連線失敗第{}次.", i);
	    		}else{
	    			logger.error("資料庫無法連線重試{}次.", i);
	    		}
    		}else{
    			logger.info("資料庫連線成功.");
    		}
    	}
        if (null == commissionCodes)
        {
            logger.info("載入代收手續費代碼.");
            commissionCodes = thirdPartyFeedbackService.loadCommissionCodes();
        }
        
        return commissionCodes;
    }

    /**
     * @param channel
     * @param fileName
     */
    private void doWriteOff(String channel, String fileName) {

        /* Select SQL Update
         * 1.確認該虛擬帳號存在，且在繳款有效期內 。
         * 2.排除WebATM通路已即時銷帳的資料 
         * 3.虛擬帳號已銷帳完成，且交易日期、時間、金額與回饋檔案相同，
         * 4.無法銷帳出Error。                                                 
         */

        try{
            this.thirdPartyFeedbackService.writeoffByFile(fileName);
            logger.info("銷帳完成：{}", fileName);

        }catch (Exception ex){
            logger.error("[錯誤]" + ex.toString(), ex);         
        }



    }

    public Map<String, Object> createEmptyFeedbackLog()
    {
        Map<String, Object> rd = new HashMap<String, Object>();

        rd.put("FBFILENAME", null);
        rd.put("FBTIME", null);
        rd.put("FBCODE", null);
        rd.put("MRKEY", null);
        rd.put("ADAY", null);

        rd.put("ATIME", null);
        rd.put("TBSDY", null);
        rd.put("APTYPE", null);
        rd.put("TXNO", null);
        rd.put("DSCPT", null);

        rd.put("TXAMT", null);
        rd.put("USERNO", null);
        rd.put("ATMID", null);
        rd.put("KINBR", null);
        rd.put("TRMSEQ", null);

        rd.put("TXTNO", null);
        rd.put("TFRBK", null);
        rd.put("TFRACT", null);
        rd.put("STANBK", null);
        rd.put("STANSEQ", null);

        rd.put("EC", null);
        rd.put("FEEDBACK_TYPE", null);
        rd.put("CHANNEL", null);
        rd.put("STORE", null);
        rd.put("ACCTDATE", null);

        rd.put("BARCDOE1", null);
        rd.put("BARCDOE2", null);
        rd.put("BARCDOE3", null);
        rd.put("ERR_MSG", null);


        return rd;
    }


    /**
     * ACH扣款資訊採AP2AP方式回饋至eBilling，回饋時程為回饋時程為T+1日00:05。。
     * @param channel
     * @param processDate
     * @param commissionCode
     * @param processSysDateROC
     * @throws IOException
     */
    public void executeByDB(String channel, String processDate, String commissionCode) throws IOException
    {
    	
        Assert.notNull(channel, "[錯誤]代收通路 can't be null.");
        Assert.notNull(processDate, "[錯誤]查詢日期  can't be null.");
        
        logger.info("************************************************");
        logger.info("代收通路：{}", channel);
        logger.info("查詢日期：{}", processDate);
        logger.info("指定ACH代碼：{}", commissionCode);


        String fileName = null;
       
       if("ACH".equals(channel)){
        	/* ACH檔名  FBFILENAME = ACH.日期 */
        	fileName = channel + "." + processDate;
        }       
        else{
            logger.error("無此代收通路： {}", channel);
            return;
        }
        
        // 檢核是否已經有檔名相同且已處理過了
        if (this.thirdPartyFeedbackService.hasWriteoff(fileName))
        {
            logger.error("[錯誤]檔名 {} 於資料表FEEDBACK_LOG 中已有銷帳成功紀錄.", fileName);
            return ;
        }
        else
        {
            logger.info("刪除繳款通路銷帳日誌, 檔名 {}", fileName);
            this.thirdPartyFeedbackService.deleteLogsByFileName(fileName);
        }

        logger.info("取得資料：{}", fileName);
        
        
        /*銷帳資料  */
     
        
        String trxAcct ="";
        String trxDate = "";      
        long trxAmount = 0;
        String trxBarcode2 = "";
        String trxBarcode3 = "";
        long totalcount = 0;
        long totalamount = 0;
       
        List<Map<String, Object>> groups= new ArrayList<Map<String, Object>>();
        
        
        
        if(commissionCode.equals("ACH")){
        	/*撈取所有 有ach_ediid 的group_pk 跟  ach_ediid*/
        	groups = this.thirdPartyFeedbackService.loadAchEdiid(); 
        }else{
        	/*只取指定 ach_ediid的店家*/
        	groups = this.thirdPartyFeedbackService.queryGroupForAchEdiid(commissionCode);
        }     
        if (0 != groups.size()) {
        	
        	 /*跑迴圈 一組一組撈*/
        	for (int i = 0; i < groups.size(); i++) {
        		
        		Map<String, Object> group = groups.get(i);
        		
        		
        		String achEdiid =(String) group.get("ACH_EDIID");
        		BigDecimal groupPk =(BigDecimal) group.get("GROUP_PK");
        		String groupName =(String) group.get("GROUP_NAME");
        		
        		/* 使用 ACH_EDIID  讀取ACH資料庫 DB名稱 */
        		Map<String, Object> mapAchDBName=this.thirdPartyFeedbackService.getAchDBName(achEdiid); 
        		
        		if(null==mapAchDBName){
        			logger.error("[錯誤]無法讀取{}ACH資料庫 DB名稱 ,achEdiid：{}" ,groupName, achEdiid );    
        			continue;
        		}
        		
        		
        		String B304_ProfileID = String.valueOf(mapAchDBName.get("B304_ProfileID"));
        		
        		
        		/*讀取ACH資料庫 table名稱 */
        		Map<String, Object> mapAchTableName	=this.thirdPartyFeedbackService.getAchTableName(B304_ProfileID);        		
        		
        		if(null==mapAchTableName){
        			logger.error("[錯誤]無法讀取{}ACH資料庫 table名稱： AR_Data{}" ,groupName, B304_ProfileID );    
        			continue;
        		}

        		String B309_UploadFileDefID =String.valueOf(mapAchTableName.get("B309_UploadFileDefID"));

        		/*銷帳資料的DB名稱為"AR_Data" + B304_ProfileID*/
        		String DBName="AR_Data" + B304_ProfileID;
        		/*銷帳資料的Table名稱為 "D" + B309_UploadFileDefID*/
        		String TableName="D" + B309_UploadFileDefID;
        		
        	 		
        		/*取得銷帳資料*/
        		//listFeedbacklogFromACH =null;
        		List<Map<String, Object>> listFeedbacklogFromACH=this.thirdPartyFeedbackService.getFeedbacklogFromACH(DBName, TableName, processDate);
        	
        	if ( !listFeedbacklogFromACH.isEmpty()){
        		
        		 /* 取得帳單業者虛擬帳號作比對 */
                List<String> virtualAccountNos = this.thirdPartyFeedbackService.loadVirtualAccountNo(groupPk.toString());
              
                /*
                 * 虛擬帳號：Table名稱_F18 F18欄位，取第21位至40位，Trim掉後，取前面14碼，
                 * 虛擬帳號需檢核是否符合eBilling中的設定的虛擬帳號的前3或4碼，符合的資料就要進FEEDBACK_LOG。
                 * */
                
                //建立一個listFeedbacklog 不然原本用移除會ConcurrentModificationException 
                List<Map<String, Object>> listFeedbacklog=new ArrayList<Map<String, Object>>();
                

                for(String virtualAccountNo:virtualAccountNos){
                	
                	
                	for(Map<String, Object> element : listFeedbacklogFromACH) {
                		// use TableName 組合 Table名稱_F18              		
                		String columnF18=TableName+"_F18";
                		columnF18=(String)element.get(columnF18);
                		columnF18=columnF18.substring(20,41).trim();
                		/*檢核是否符合eBilling中的設定的虛擬帳號的前3或4碼*/
                		if(virtualAccountNo.length()==3){
                			
                			String chk=	columnF18.substring(0,3);
                			if(virtualAccountNo.equals(chk))
                			{   /*加入符合的*/
                				listFeedbacklog.add(element);
                			}
                			
                		}else if(virtualAccountNo.length()==4){
                			
                			String chk=	columnF18.substring(0,4);
                			if(virtualAccountNo.equals(chk))
                			{	/*加入符合的*/
                				listFeedbacklog.add(element);
                			}
                			
                		}else{
                			
                			logger.error("[錯誤]虛擬帳號位數有誤：{}" , virtualAccountNo); 
                			
                		}
                		
                    }
                	
                	
                	/*將整理過的資料 寫入 feedbacklog*/
                	for(Map<String, Object> element : listFeedbacklog) {              		
                		
                		/* ---- ACH格式 ----  */  
                    	
                		 /*
                         * 虛擬帳號：Table名稱_F18 F18欄位，取第21位至40位，Trim掉後，取前面14碼，
                         * 虛擬帳號需檢核是否符合eBilling中的設定的虛擬帳號的前3或4碼，符合的資料就要進FEEDBACK_LOG。
                         * */
                    	/* 虛擬帳號：* TableName_F18 Trim掉後若長度為14取前面14碼
                    	 * TableName_F18 Trim掉後若長度為16取前面16碼*/
                		// use TableName                		
                		String columnF18=TableName+"_F18";
                		 columnF18=(String)element.get(columnF18);
                		if(16==columnF18.substring(20,41).trim().length()){
                			trxAcct = columnF18.substring(20,41).trim().substring(0,16);
                		}else{
                			trxAcct = columnF18.substring(20,41).trim().substring(0,14);	
                		}
                		// use TableName                
                		String columnF101=TableName+"_F101";
                    	/*繳款日期：TableName_F101 民國*/
                    	 columnF101=(String)element.get(columnF101);
                    	/*aday轉西元*/
                    	trxDate = String.valueOf((Integer.parseInt(columnF101) + 19110000));
                    	
                    	/*繳款金額：TableName_F09(money型態)*/
                    	String columnF09Name=TableName+"_F09";
                    	BigDecimal columnF09=(BigDecimal)element.get(columnF09Name);
                    	/* 交易金額 */ /*TXAMT＝TableName_F09*/                       
                        trxAmount =  columnF09.longValue();

                        /*BARCDOE2 =虛擬帳號*/
                        if(14==trxAcct.length()){
                        	trxBarcode2=trxAcct+"00";
                        }else{
                        	trxBarcode2=trxAcct;
                        }
                        
						/*BARCDOE3 =虛擬帳號*/
                        trxBarcode3=trxAcct;
                        /* 交易筆數加總*/
                        totalcount++; 
                        /* 交易金額加總 */
                        totalamount = totalamount + trxAmount;
                        
                        
                        Map<String, Object> feedBackLog = createEmptyFeedbackLog();
                        feedBackLog.put("FBFILENAME", fileName);/*FBFILENAME = ACH.日期   直接用fileName*/
                        feedBackLog.put("CHANNEL", channel); /*CHANNEL=ACH*/
                        feedBackLog.put("ADAY", trxDate);  /*ADAY 用系統日*/
                        feedBackLog.put("BARCDOE2", trxBarcode2);
                        feedBackLog.put("BARCDOE3", trxBarcode3);
                        feedBackLog.put("TXAMT", trxAmount);
                        feedBackLog.put("USERNO", trxBarcode3);//虛擬帳號 /*USERNO =虛擬帳號*/
                        feedBackLog.put("ATIME", "00000000");//顧客繳費時間  /*ATIME＝00000000*/
                        feedBackLog.put("FEEDBACK_TYPE", new Integer(2)); //回饋種類2 : thirdParty(便利商店、郵局等)
                        feedBackLog.put("FBTIME", new Date()); //銷帳時間
                        feedBackLog.put("FBCODE", "0");//銷帳結果 

                        /* Insert to 銷帳Log Table 檔名 + 上面所有資料*/  
                        this.thirdPartyFeedbackService.addFeedbackLog(feedBackLog);  
                        
                        
                	}
                	
                	
                	}//virtualaccount end
        		}else
                {
                    logger.info("今日無{}銷帳資料，DB：{}  " ,groupName+processDate, DBName+".dbo."+TableName );                      
                    continue;
                }  
        	
        	}// group foreach end
        	/*全部撈完後 銷帳 */
        	  logger.info("銷帳總筆數：{}", totalcount);
              logger.info("銷帳總金額：{}", totalamount); 
              doWriteOff(channel, fileName);
        	
           
           
           
     }else//group size end
          {
              logger.info("無設定帳單業者ACH代碼：{}" , fileName);      
          }
        
      

    }
    
public  String getHoliday(String processDate){
    	
    	return this.thirdPartyFeedbackService.getHoliday(processDate);
   	
    }


}
